package crypt

import (
	"crypto/ed25519"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	"os"
	"regexp"
	"strings"

	"gitee.com/851537/gbase"
)

type Ed25519 struct {
	Base
	PublicKey  ed25519.PublicKey
	PrivateKey ed25519.PrivateKey
}

// 格式化私钥 - 将各种不规范的私钥格式转换为标准的PEM格式
func (e *Ed25519) FormatPrivateKey(privateKey string) (string, error) {
	if privateKey == "" {
		return "", errors.New("私钥不能为空")
	}

	// 去除前后空白字符
	privateKey = strings.TrimSpace(privateKey)

	// 1. 检查是否已经是标准格式 (带换行符的PEM格式)
	if e.isStandardPEMFormat(privateKey) {
		return privateKey, nil
	}

	// 2. 提取base64编码的私钥内容
	base64Content, err := e.extractBase64Content(privateKey)
	if err != nil {
		return "", err
	}

	// 3. 验证base64内容的有效性
	if err := e.validateBase64Content(base64Content); err != nil {
		return "", err
	}

	// 4. 格式化为标准PEM格式
	return e.formatToStandardPEM(base64Content), nil
}

// 检查是否已经是标准的PEM格式
func (e *Ed25519) isStandardPEMFormat(privateKey string) bool {
	// 标准格式应该包含换行符且格式正确
	if !strings.Contains(privateKey, "\n") {
		return false
	}

	// 验证PEM格式
	block, _ := pem.Decode([]byte(privateKey))
	if block == nil || block.Type != "PRIVATE KEY" {
		return false
	}

	return true
}

// 提取base64编码的私钥内容
func (e *Ed25519) extractBase64Content(privateKey string) (string, error) {
	// 情况1: 完整的PEM格式但没有换行符
	// -----BEGIN PRIVATE KEY-----MC4CAQAwBQYDK2VwBCIEILkEwBwaTeC9MafMF1poV21ikkbN3VtVVUk3bzeKense-----END PRIVATE KEY-----
	if strings.HasPrefix(privateKey, "-----BEGIN") && strings.HasSuffix(privateKey, "-----END PRIVATE KEY-----") {
		// 提取中间的base64内容
		re := regexp.MustCompile(`-----BEGIN[^-]*-----([A-Za-z0-9+/=]+)-----END[^-]*-----`)
		matches := re.FindStringSubmatch(privateKey)
		if len(matches) > 1 {
			return matches[1], nil
		}
	}

	// 情况2: 只有base64内容，没有PEM头尾
	// MC4CAQAwBQYDK2VwBCIEILkEwBwaTeC9MafMF1poV21ikkbN3VtVVUk3bzeKense
	if e.isValidBase64(privateKey) {
		return privateKey, nil
	}

	// 情况3: 带有换行符但格式不规范的PEM
	// -----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEILkEwBwaTeC9MafMF1poV21ikkbN3VtVVUk3bzeKense\n-----END PRIVATE KEY-----\n

	// 先处理字面意思的 \n 字符串（不是真正的换行符）
	if strings.Contains(privateKey, "\\n") {
		privateKey = strings.ReplaceAll(privateKey, "\\n", "\n")
	}

	lines := strings.Split(privateKey, "\n")
	var base64Lines []string

	for _, line := range lines {
		line = strings.TrimSpace(line)
		// 跳过PEM头尾和空行
		if strings.HasPrefix(line, "-----") || line == "" {
			continue
		}
		// 收集base64内容行
		if e.isValidBase64(line) {
			base64Lines = append(base64Lines, line)
		}
	}

	if len(base64Lines) > 0 {
		return strings.Join(base64Lines, ""), nil
	}

	// 情况4: 十六进制格式
	if e.isHexString(privateKey) {
		return e.hexToBase64(privateKey)
	}

	// 情况5: 其他可能的分隔符
	// 移除常见的分隔符和空白字符
	cleaned := regexp.MustCompile(`[\s\-_:,]+`).ReplaceAllString(privateKey, "")
	if e.isValidBase64(cleaned) {
		return cleaned, nil
	}

	return "", errors.New("无法识别的私钥格式")
}

// 验证base64内容是否为有效的ED25519私钥
func (e *Ed25519) validateBase64Content(base64Content string) error {
	// 解码base64
	decoded, err := base64.StdEncoding.DecodeString(base64Content)
	if err != nil {
		return fmt.Errorf("base64解码失败: %v", err)
	}

	// 尝试解析为PKCS8格式的私钥
	_, err = x509.ParsePKCS8PrivateKey(decoded)
	if err != nil {
		return fmt.Errorf("不是有效的PKCS8私钥格式: %v", err)
	}

	return nil
}

// 格式化为标准PEM格式
func (e *Ed25519) formatToStandardPEM(base64Content string) string {
	// 按64个字符一行分割base64内容
	var lines []string
	for i := 0; i < len(base64Content); i += 64 {
		end := i + 64
		if end > len(base64Content) {
			end = len(base64Content)
		}
		lines = append(lines, base64Content[i:end])
	}

	// 构建标准PEM格式
	var result strings.Builder
	result.WriteString("-----BEGIN PRIVATE KEY-----\n")
	for _, line := range lines {
		result.WriteString(line)
		result.WriteString("\n")
	}
	result.WriteString("-----END PRIVATE KEY-----\n")

	return result.String()
}

// 检查字符串是否为有效的base64
func (e *Ed25519) isValidBase64(s string) bool {
	if len(s) == 0 {
		return false
	}
	// base64字符集检查
	matched, _ := regexp.MatchString(`^[A-Za-z0-9+/]*={0,2}$`, s)
	if !matched {
		return false
	}
	// 尝试解码
	_, err := base64.StdEncoding.DecodeString(s)
	return err == nil
}

// 检查字符串是否为十六进制
func (e *Ed25519) isHexString(s string) bool {
	if len(s) == 0 {
		return false
	}
	// 移除可能的0x前缀
	if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") {
		s = s[2:]
	}
	matched, _ := regexp.MatchString(`^[0-9a-fA-F]+$`, s)
	return matched && len(s)%2 == 0
}

// 十六进制转base64
func (e *Ed25519) hexToBase64(hexStr string) (string, error) {
	// 移除0x前缀
	if strings.HasPrefix(hexStr, "0x") || strings.HasPrefix(hexStr, "0X") {
		hexStr = hexStr[2:]
	}

	// 解码十六进制
	decoded := make([]byte, len(hexStr)/2)
	for i := 0; i < len(hexStr); i += 2 {
		var b byte
		_, err := fmt.Sscanf(hexStr[i:i+2], "%02x", &b)
		if err != nil {
			return "", fmt.Errorf("十六进制解码失败: %v", err)
		}
		decoded[i/2] = b
	}

	// 编码为base64
	return base64.StdEncoding.EncodeToString(decoded), nil
}

// -------------------------
func (this *Ed25519) LoadPrivateKey(privateKeyData []byte) error {
	// 解析PEM格式
	block, _ := pem.Decode(privateKeyData)
	if block == nil {
		// 如果不是PEM格式，尝试直接解析为二进制格式
		if len(privateKeyData) == ed25519.PrivateKeySize {
			privKey := make(ed25519.PrivateKey, ed25519.PrivateKeySize)
			copy(privKey, privateKeyData)
			this.PrivateKey = privKey
			return nil
		}
		return errors.New("私钥文件格式错误：非PEM格式且长度不符合ED25519私钥长度")
	}

	// 检查PEM块类型
	if block.Type != "PRIVATE KEY" && block.Type != "OPENSSH PRIVATE KEY" && block.Type != "ED25519 PRIVATE KEY" {
		return fmt.Errorf("私钥类型错误: %s", block.Type)
	}

	// 解析私钥
	privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		// 尝试解析PKCS1格式
		privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
		if err != nil {
			return fmt.Errorf("解析私钥失败: %w", err)
		}
	}

	// 转换为ed25519.PrivateKey类型
	ed25519Key, ok := privateKey.(ed25519.PrivateKey)
	if !ok {
		return errors.New("私钥不是ED25519类型")
	}
	this.PrivateKey = ed25519Key
	return nil
}

func (this *Ed25519) LoadPrivateKeyFromFile(filePath string) error {
	// 读取私钥文件
	privKeyData, err := os.ReadFile(filePath)
	if err != nil {
		return fmt.Errorf("读取私钥文件失败: %w", err)
	}
	return this.LoadPrivateKey(privKeyData)
}

func (this *Ed25519) LoadPublicKey(publicKeyData []byte) error {
	// 解析PEM格式
	block, _ := pem.Decode(publicKeyData)
	if block == nil {
		// 如果不是PEM格式，尝试直接解析为二进制格式
		if len(publicKeyData) == ed25519.PublicKeySize {
			pubKey := make(ed25519.PublicKey, ed25519.PublicKeySize)
			copy(pubKey, publicKeyData)
			this.PublicKey = pubKey
			return nil
		}
		return errors.New("公钥文件格式错误：非PEM格式且长度不符合ED25519公钥长度")
	}

	// 检查PEM块类型
	if block.Type != "PUBLIC KEY" && block.Type != "OPENSSH PUBLIC KEY" && block.Type != "ED25519 PUBLIC KEY" {
		return fmt.Errorf("公钥类型错误: %s", block.Type)
	}

	// 解析公钥
	publicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return fmt.Errorf("解析公钥失败: %w", err)
	}

	// 转换为ed25519.PublicKey类型
	ed25519Key, ok := publicKey.(ed25519.PublicKey)
	if !ok {
		return errors.New("公钥不是ED25519类型")
	}
	this.PublicKey = ed25519Key
	return nil
}

func (this *Ed25519) LoadPublicKeyFromFile(filePath string) error {
	// 读取公钥文件
	pubKeyData, err := os.ReadFile(filePath)
	if err != nil {
		return fmt.Errorf("读取公钥文件失败: %w", err)
	}
	return this.LoadPublicKey(pubKeyData)
}

func (this *Ed25519) HasPrivateKey() bool {
	return this.PrivateKey != nil
}

func (this *Ed25519) HasPublicKey() bool {
	return this.PublicKey != nil
}

func (this *Ed25519) Sign(payload []byte) (sign []byte, err error) {
	if !this.HasPrivateKey() && this.privateKeyFile.Path == "" {
		return nil, errors.New("未设置私钥或私钥文件")
	}
	if !this.HasPrivateKey() {
		if err = this.LoadPrivateKeyFromFile(this.privateKeyFile.Path); err != nil {
			return nil, err
		}
	}
	sign = ed25519.Sign(this.PrivateKey, payload)
	return
}

func (this *Ed25519) SignString(payload string) (sign string, err error) {
	var bsign []byte
	bsign, err = this.Sign([]byte(payload))
	if err != nil {
		return "", err
	}
	sign = string(bsign)
	return
}

func (this *Ed25519) SignB64(payload string) (sign string, err error) {
	var tmpSign []byte
	tmpSign, err = this.Sign([]byte(payload))
	if err != nil {
		return "", err
	}
	sign = base64.StdEncoding.EncodeToString(tmpSign)
	return
}

func (this *Ed25519) Verify(sign []byte, payload []byte) (err error) {
	if !this.HasPublicKey() && this.publicKeyFile.Path == "" {
		return errors.New("未设置公钥或公钥文件")
	}
	if !this.HasPublicKey() {
		if err = this.LoadPublicKeyFromFile(this.publicKeyFile.Path); err != nil {
			return err
		}
	}
	if !ed25519.Verify(this.PublicKey, payload, sign) {
		return errors.New("签名验证失败")
	}
	return nil
}

func (this *Ed25519) VerifyB64(sign string, payload string) (err error) {
	signBytes, err := base64.StdEncoding.DecodeString(sign)
	if err != nil {
		return fmt.Errorf("解码签名失败: %w", err)
	}
	return this.Verify(signBytes, []byte(payload))
}

func NewEd25519(opts ...gbase.Option[*Ed25519]) *Ed25519 {
	obj := new(Ed25519)
	for _, v := range opts {
		v(obj)
	}
	return obj
}

// 通过直接提供私钥和公钥初始化
func NewEd25519WithPem(privateKey, publicKey string) (obj *Ed25519, err error) {
	obj = NewEd25519()

	if privateKey != "" {
		if !obj.isStandardPEMFormat(privateKey) {
			privateKey, err = obj.FormatPrivateKey(privateKey)
			if err != nil {
				return nil, errors.New("格式化私钥失败")
			}
		}
		if err = obj.LoadPrivateKey([]byte(privateKey)); err != nil {
			return
		}
	}
	if publicKey != "" {
		if err = obj.LoadPublicKey([]byte(publicKey)); err != nil {
			return
		}
	}

	return obj, nil
}
